/*
 * SGX Public License Notice This software is the intellectual property of SGX.
 * The program may be used only in accordance with the terms of the license
 * agreement you entered into with SGX. 2003 Singapore Exchange Pte Ltd (SGX).
 * All rights reserved. 2 Shenton Way / #22-00 SGX Centre 1 Singapore( 068804 )
 */
package com.hbyj.gps;

/**
 * @author John
 * @since Jul 30, 2010
 */
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Observable;
import java.util.TooManyListenersException;
import java.util.Date;
//GPrmc类

class GpsJWInfo
{
	float plon;
	float plat;
	float height;
	/*Date ptime;
	String pstatus;
	float plon;
	float plat;
	String plonew;
	String platns;
	float pspeed;
	String pdirect;	*/
}

/**
 * 串口数据读取类,用于windows的串口数据读取
 * 
 * @author Macro Lu
 * @version 2007-4-4
 */
public class SerialReader extends Observable implements Runnable,
    SerialPortEventListener
{
    static CommPortIdentifier portId;
    int delayRead = 200;
    int numBytes; // buffer中的实际数据字节数
    private static byte[] readBuffer = new byte[4096]; // 4k的buffer空间,缓存串口读入的数据
    static Enumeration portList;
    InputStream inputStream;
    SerialPort serialPort;
    HashMap serialParams;
    // 端口读入数据事件触发后,等待n毫秒后再读取,以便让数据一次性读完
    public static final String PARAMS_DELAY = "delay read"; // 延时等待端口数据准备的时间
    public static final String PARAMS_TIMEOUT = "timeout"; // 超时时间
    public static final String PARAMS_PORT = "port name"; // 端口名称
    public static final String PARAMS_DATABITS = "data bits"; // 数据位
    public static final String PARAMS_STOPBITS = "stop bits"; // 停止位
    public static final String PARAMS_PARITY = "parity"; // 奇偶校验
    public static final String PARAMS_RATE = "rate"; // 波特率
    private static String jwd;
    private static float jd;
    private static float wd;
    private static float gd;
    /**
     * 初始化端口操作的参数.
     * 
     * @see
     */
    public SerialReader( HashMap params )
    {
        serialParams = params;
        init();
    }

    private void init()
    {
        try
        {
            // 参数初始化
            int timeout = Integer.parseInt( serialParams.get( PARAMS_TIMEOUT )
                .toString() );
            int rate = Integer.parseInt( serialParams.get( PARAMS_RATE )
                .toString() );
            int dataBits = Integer.parseInt( serialParams.get( PARAMS_DATABITS )
                .toString() );
            int stopBits = Integer.parseInt( serialParams.get( PARAMS_STOPBITS )
                .toString() );
            int parity = Integer.parseInt( serialParams.get( PARAMS_PARITY )
                .toString() );
            delayRead = Integer.parseInt( serialParams.get( PARAMS_DELAY )
                .toString() );
            String port = serialParams.get( PARAMS_PORT ).toString();
            // 打开端口
            portId = CommPortIdentifier.getPortIdentifier( port );
            serialPort = ( SerialPort ) portId.open( "SerialReader", timeout );
            inputStream = serialPort.getInputStream();
            serialPort.addEventListener( this );
            serialPort.notifyOnDataAvailable( true );
            serialPort.setSerialPortParams( rate, dataBits, stopBits, parity );
        }
        catch ( PortInUseException e )
        {
            System.out.println( "端口已经被占用!" );
            e.printStackTrace();
        }
        catch ( TooManyListenersException e )
        {
            System.out.println( "端口监听者过多!" );
            e.printStackTrace();
        }
        catch ( UnsupportedCommOperationException e )
        {
            System.out.println( "端口操作命令不支持!" );
            e.printStackTrace();
        }
        catch ( NoSuchPortException e )
        {
            System.out.println( "端口不存在!" );
            e.printStackTrace();
        }
        catch ( IOException e )
        {
            e.printStackTrace();
        }
        Thread readThread = new Thread( this );
        readThread.start();
    }

    /**
     * Method declaration
     * 
     * @see
     */
    public void run()
    {
        try
        {
            Thread.sleep( 100 );
        }
        catch ( InterruptedException e )
        {
        }
    }

    /**
     * Method declaration
     * 
     * @param event
     * @see
     */
    public void serialEvent( SerialPortEvent event )
    {
        try
        {
            // 等待1秒钟让串口把数据全部接收后在处理
            Thread.sleep( delayRead );
            System.out.println( "serialEvent[" + event.getEventType() + "]    " );
        }
        catch ( InterruptedException e )
        {
            e.printStackTrace();
        }
        switch ( event.getEventType() )
        {
            case SerialPortEvent.BI: // 10
            case SerialPortEvent.OE: // 7
            case SerialPortEvent.FE: // 9
            case SerialPortEvent.PE: // 8
            case SerialPortEvent.CD: // 6
            case SerialPortEvent.CTS: // 3
            case SerialPortEvent.DSR: // 4
            case SerialPortEvent.RI: // 5
            case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2
                break;
            case SerialPortEvent.DATA_AVAILABLE: // 1
                try
                {
                    // 多次读取,将所有数据读入
                     while (inputStream.available() > 0) {
                     numBytes = inputStream.read(readBuffer);
                     }
//                    numBytes = inputStream.read( readBuffer );
                
              
                    changeMessage( readBuffer, numBytes );
                }
                catch ( IOException e )
                {
                    e.printStackTrace();
                }
                break;
        }
    }

    // 通过observer pattern将收到的数据发送给observer
    // 将buffer中的空字节删除后再发送更新消息,通知观察者
    public void changeMessage( byte[] message, int length )
    {
        setChanged();
        byte[] temp = new byte[length];
        System.arraycopy( message, 0, temp, 0, length );
        // System.out.println("msg[" + numBytes + "]: [" + new String(temp) + "]");
        
        String tmp = new String((byte[])temp);
    	String gprmcstr = parserNEMA(tmp);
    	GpsJWInfo gpsinfo = new GpsJWInfo();
    	gpsinfo = createGPSData(gprmcstr);
    	jd = gpsinfo.plon;
    	wd = gpsinfo.plat;
    	gd = gpsinfo.height;
    	System.out.println("读取到的经纬度："+"["+gpsinfo.plon+","+gpsinfo.plat+"]");
 
        
        notifyObservers( temp );
    }

    static void listPorts()
    {
        Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
        while ( portEnum.hasMoreElements() )
        {
            CommPortIdentifier portIdentifier = ( CommPortIdentifier ) portEnum
                .nextElement();
            System.out.println( portIdentifier.getName() + " - "
                + getPortTypeName( portIdentifier.getPortType() ) );
        }
    }

    static String getPortTypeName( int portType )
    {
        switch ( portType )
        {
            case CommPortIdentifier.PORT_I2C:
                return "I2C";
            case CommPortIdentifier.PORT_PARALLEL:
                return "Parallel";
            case CommPortIdentifier.PORT_RAW:
                return "Raw";
            case CommPortIdentifier.PORT_RS485:
                return "RS485";
            case CommPortIdentifier.PORT_SERIAL:
                return "Serial";
            default:
                return "unknown type";
        }
    }

    /**
     * @return A HashSet containing the CommPortIdentifier for all serial ports
     *         that are not currently being used.
     */
    public static HashSet<CommPortIdentifier> getAvailableSerialPorts()
    {
        HashSet<CommPortIdentifier> h = new HashSet<CommPortIdentifier>();
        Enumeration thePorts = CommPortIdentifier.getPortIdentifiers();
        while ( thePorts.hasMoreElements() )
        {
            CommPortIdentifier com = ( CommPortIdentifier ) thePorts
                .nextElement();
            switch ( com.getPortType() )
            {
                case CommPortIdentifier.PORT_SERIAL:
                    try
                    {
                        CommPort thePort = com.open( "CommUtil", 50 );
                        thePort.close();
                        h.add( com );
                    }
                    catch ( PortInUseException e )
                    {
                        System.out.println( "Port, " + com.getName()
                            + ", is in use." );
                    }
                    catch ( Exception e )
                    {
                        System.out.println( "Failed to open port "
                            + com.getName() + e );
                    }
            }
        }
        return h;
    }
    
   /////////////////////////////////////////////////////////
    //解析NEMA数据
    public String parserNEMA(String msgStr)
    {
    	int pos = msgStr.indexOf("$GPGGA");
    	String gprmcStr = (pos>-1)?msgStr.substring(pos):null;
    	String gprmc = gprmcStr;
    	if(gprmcStr != null){
    		gprmcStr= gprmcStr.substring(0,70);
    		
    		int pos2 = gprmcStr.indexOf("$", 1);
    		gprmc = (pos2>-1)?gprmcStr.substring(0,pos2-1):gprmcStr;	
    	} 	
    	System.out.println("这里开始");
    	System.out.println(gprmc);
    	System.out.println("这里结束");
    	return gprmc;
    }
      
    public GpsJWInfo createGPSData(String gprmcStr)
    {
    	float fplat,fplon;
    	int degree;
    	if(gprmcStr==null)
    		return null;
    	GpsJWInfo gpsinfo = new GpsJWInfo();
    	String[] source = gprmcStr.split(",");
    	if(source !=null && source.length>=12)
    	{
    		if(source[3].length()>0 && source[2].length()>2)
    		{
    			gpsinfo.plat = Float.valueOf(source[2]);  
    		}
    		else
    		{
    			gpsinfo.plat= 0;
    		}
    		//经度  
    		if (source[5].length() > 0 && source[4].length() > 3)  
            {  
    			gpsinfo.plon = Float.valueOf(source[4]); 
    		}  
    		else  
    		{  
    			gpsinfo.plon= 0;  
    		} 
    		//高度
    		if(source[9].length()>0&&source[10].length()>0&&source[11].length()>0&&source[12].length()>0){
    			gpsinfo.height = Float.valueOf(source[9])+Float.valueOf(source[11]);
    		}else{
    			gpsinfo.height = 0;
    		}
    	}
    	//转换成度
    	degree = (int)gpsinfo.plat/100;
    	fplat = degree+(gpsinfo.plat-degree*100)/60;
    	degree = (int)gpsinfo.plon/100;
    	fplon = degree+(gpsinfo.plon-degree*100)/60;
    	gpsinfo.plat = fplat;
    	gpsinfo.plon = fplon;
    	return gpsinfo;	
    }
    
    public String GetJWD(){
    	
    	jwd = String.valueOf(jd)+","+String.valueOf(wd)+","+String.valueOf(gd);
    	return jwd;
    }
    
      
  
    
}
